package dletc.thread;

/**
 * 多线程课堂笔记：
 * 1.什么是进程？ 什么是线程？
 * 进程是一个应用程序被执行。
 * 线程是一个进程中的执行场景/执行单元
 * 一个进程可以启动多个线程。
 * <p>
 * 2.对于java程序来说，当在DOS命令窗口中输入：
 * java HelloWorld 回车之后，会先启动JVM，而JVM就算一个进程
 * JVN再启动一个主线程调用main方法，同时再启动一个垃圾回收线程负责看护，回收垃圾
 * 最起码，现在的java程序中至少有两个线程并发，一个是垃圾回收线程，一个是执行main方法的主线程。
 * <p>
 * 3.进程和线程是什么关系? 举例说明：
 * 杀毒软件就是一个进程，里面的各个功能模块（体检、病毒查杀、垃圾清理等）都是线程。
 * 注意：进程之间的内存独立不共享（两个独立的程序）
 * 线程之间（在java语言中）：
 * 【**线程A和线程B，堆内存和方法区内存共享，但是栈内存独立，一个线程一个栈**。】
 * 假设启动10个线程，会有10个栈空间，栈和栈之间独立，互不干扰，各自执行各自的，这就是线程并发。
 * java中之所以有多线程机制，就是为了提高程序的处理效率。
 * 4.思考问题：
 * 使用了多线程机制之后，main方法结束，是不是有可能程序也不会结束，main方法结束只是
 * 主线程结束了，主栈空了其他的栈（线程）可能还在运行（压栈弹栈）。
 * <p>
 * 5.对于单核CPU和多核CPU的理解：
 * 多核CPU：实现多线程并发是没有问题的，就相当于4个核在同一时间，执行不同的事情，效率高。 进程是并行
 * 单核CPU：假的多线程并发  原理： 线程之间是频繁切换的，所有造成的假象就是每一个线程都是同时工作的；
 * 一个程序就是一个进程，一个进程内存在1~N个进程，线程开启不一定立即执行，每个进程都需要抢cpu，抢到了才能运行。
 * <p>
 * 6.java语言中，实现线程的两种方式：
 * 第一种方式：编写一个类，直接继承java.lang.Thread，重写run方法。
 * 第二种方式：编写一个类，实现java.lang.Runnable接口，实现run方法。
 * 注意：第二种方式实现接口比较常用，因为一个类实现了接口，它还可以去继承其他的类，更灵活，面向接口编程。
 * <p>
 * 7.java中三大变量：实例变量（堆中）  静态变量（方法区中） 局部变量（栈中）
 * 多线程并发问题，三个条件：条件1：多线程并发   条件2： 有共享数据   条件3： 共享数据有被修改的行为
 * 线程共享堆和方法区中的数据，栈是独立的，所以局部变量没有线程安全问题，实例变量和静态变量会有线程安全的问题。
 * 8. 线程分类：用户线程，守护线程
 * 虚拟机必须确保用户线程执行完毕；
 * 虚拟机不用等待守护线程执行完毕；
 */

/*
* 面试题：2个线程 按交替打印 1 2 3 4
* 解题思路：交替打印通过wait和notifyAll可以做到。
* 注意点：共享数据不能直接使用基本数据类型或包装类，需要用引用类型承载，不然会报错。
* */
public class Demo {
    public static void main(String[] args) {
        Int anInt = new Int();
        anInt.num = 1;
        /*
        Thread thread1 = new Thread(new MyThread01(anInt), "1");
        Thread thread2 = new Thread(new MyThread02(anInt), "2");
        thread1.start();
        thread2.start();
        */
        new Thread(new MyThread03(anInt),"1").start();
        new Thread(new MyThread03(anInt),"2").start();

    }
}

class MyThread01 implements Runnable {

    public Int anInt;

    public MyThread01(Int anInt) {
        this.anInt = anInt;
    }

    @Override
    public void run() {
        while (anInt.num <= 100) {
            synchronized (anInt) {
                if (anInt.num % 2 == 0) {
                    try {
                        anInt.wait();
                    } catch (InterruptedException e) {
                    }
                }
                System.out.println(Thread.currentThread().getName() + "---" + anInt.num++);
                anInt.notifyAll();
            }
        }

    }
}

class MyThread02 implements Runnable {

    public Int anInt;

    public MyThread02(Int anInt) {
        this.anInt = anInt;
    }

    @Override
    public void run() {
        while (anInt.num <= 100) {
            synchronized (anInt) {
                if (anInt.num % 2 != 0) {
                    try {
                        anInt.wait();
                    } catch (InterruptedException e) {
                    }
                }
                System.out.println(Thread.currentThread().getName() + "---" + anInt.num++);
                anInt.notifyAll();
            }
        }

    }
}

class MyThread03 implements Runnable{

    Int anInt;

    public MyThread03(Int anInt){
        this.anInt = anInt;
    }

    @Override
    public void run() {
        while(anInt.num < 5){
            synchronized (anInt){
                anInt.notifyAll();
                System.out.println(Thread.currentThread().getName() + "   " + anInt.num++);
                try {
                    anInt.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

class Int{
    int num;
        }


